package com.jetpackframework.virtual;

import android.os.Build;

import com.jetpackframework.Reflector;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * SO文件的加载  采用文件覆盖的方式实现的  旧的so文件不做保留
 */
public class SoLoader {
    public static void injectLibraryInternal(ClassLoader classLoader, File soDir){
        if (Build.VERSION.SDK_INT >= 25){
            V25.install(classLoader, soDir);
        } else if (Build.VERSION.SDK_INT >= 23){
            V23.install(classLoader,soDir);
        }else if (Build.VERSION.SDK_INT >= 14){
            V14.install(classLoader, soDir);
        }else {
            V4.install(classLoader, soDir);
        }
    }

    private static final class V25{
        public static void install(ClassLoader classLoader, File soDir) {
            try {
                Object pathList = Reflector.with(classLoader).field("pathList").get();
                List<File> origLibDirs = Reflector.with(pathList).field("nativeLibraryDirectories").get();
                if (origLibDirs == null){
                    origLibDirs = new ArrayList<>(2);
                }
                final Iterator<File> libDirIt = origLibDirs.iterator();
                while (libDirIt.hasNext()) {
                    final File libDir = libDirIt.next();
                    if (soDir.equals(libDir)) {
                        libDirIt.remove();
                        break;
                    }
                }
                origLibDirs.add(0, soDir);
                List<File> origSystemLibDirs = Reflector.with(pathList).field("systemNativeLibraryDirectories").get();
                if (origSystemLibDirs == null) {
                    origSystemLibDirs = new ArrayList<>(2);
                }
                final List<File> newLibDirs = new ArrayList<>(origLibDirs.size() + origSystemLibDirs.size() + 1);
                newLibDirs.addAll(origLibDirs);
                newLibDirs.addAll(origSystemLibDirs);

                Object elements = Reflector.with(pathList).method("makePathElements", List.class).call(newLibDirs);
                Reflector.with(pathList).field("nativeLibraryPathElements").set(elements);
            } catch (Reflector.ReflectedException e) {
                e.printStackTrace();
                V23.install(classLoader,soDir);
            }
        }
    }
    private static final class V23{

        public static void install(ClassLoader classLoader, File soDir) {
            try {
                Object pathList = Reflector.with(classLoader).field("pathList").get();
                List<File> origLibDirs = Reflector.with(pathList).field("nativeLibraryDirectories").get();
                if (origLibDirs == null){
                    origLibDirs = new ArrayList<>(2);
                }
                final Iterator<File> libDirIt = origLibDirs.iterator();
                while (libDirIt.hasNext()) {
                    final File libDir = libDirIt.next();
                    if (soDir.equals(libDir)) {
                        libDirIt.remove();
                        break;
                    }
                }
                origLibDirs.add(0, soDir);
                List<File> origSystemLibDirs = Reflector.with(pathList).field("systemNativeLibraryDirectories").get();
                if (origSystemLibDirs == null) {
                    origSystemLibDirs = new ArrayList<>(2);
                }
                final List<File> newLibDirs = new ArrayList<>(origLibDirs.size() + origSystemLibDirs.size() + 1);
                newLibDirs.addAll(origLibDirs);
                newLibDirs.addAll(origSystemLibDirs);
                ArrayList<IOException> suppressedExceptions = new ArrayList<>();

                Object elements = Reflector.with(pathList).method("makePathElements", List.class, File.class, List.class).call(newLibDirs, null, suppressedExceptions);
                Reflector.with(pathList).field("nativeLibraryPathElements").set(elements);
            }catch (Reflector.ReflectedException e){
                e.printStackTrace();
                V14.install(classLoader,soDir);
            }
        }
    }
    private static final class V14{

        public static void install(ClassLoader classLoader, File soDir) {
            try {
                Object pathList = Reflector.with(classLoader).field("pathList").get();
                File[] origLibDirs = Reflector.with(pathList).field("nativeLibraryDirectories").get();
                final List<File> newNativeLibDirList = new ArrayList<>(origLibDirs.length + 1);
                newNativeLibDirList.add(soDir);
                for (File origNativeLibDir : origLibDirs) {
                    if (!soDir.equals(origNativeLibDir)) {
                        newNativeLibDirList.add(origNativeLibDir);
                    }
                }
                Reflector.with(pathList).field("nativeLibraryDirectories").set(newNativeLibDirList.toArray(new File[0]));
            } catch (Reflector.ReflectedException e) {
                e.printStackTrace();
            }
        }
    }
    private static final class V4{

        public static void install(ClassLoader classLoader, File soDir) {

        }
    }
}
